//! src/mem/dump.rs
//!
//! 内存诊断和导出模块
//!
//! 提供以下功能：
//! - 以多种格式导出内存内容
//! - 内存使用统计和分析
//! - 智能诊断工具
//!
//! 关键特性：
//! 1. 智能空白行压缩 - 自动检测并压缩连续空白行
//! 2. 精确地址范围 - 只显示有实际数据的区域
//! 3. 详细统计信息 - 内存使用率、空白字节数等
//! 4. 可配置输出 - 支持自定义行格式、ASCII显示等
//! 5. 高效处理大内存 - 使用行数限制和智能压缩

use super::Memory;
use std::io::{Write, Result as IoResult};

/// 内存转储配置选项
///
/// 允许用户自定义内存转储的输出格式和行为
#[derive(Debug, Clone)]
pub struct DumpOptions {
    /// 每行显示的字节数（默认为16）
    pub bytes_per_line: usize,
    
    /// 最大显示行数（防止大内存导致输出过大）
    pub max_lines: usize,
    
    /// 是否在右侧显示ASCII表示（增强可读性）
    pub show_ascii: bool,
    
    /// 是否压缩连续的空白行（显著减少输出大小）
    pub compress_empty_lines: bool,
    
    /// 是否在每行开头显示行号（便于导航）
    pub show_line_numbers: bool,
}

impl Default for DumpOptions {
    /// 默认配置：平衡可读性和输出大小
    fn default() -> Self {
        Self {
            bytes_per_line: 16,
            max_lines: 1024,
            show_ascii: true,
            compress_empty_lines: true,
            show_line_numbers: true,
        }
    }
}

/// 内存分析统计信息
///
/// 提供内存使用情况的量化指标
#[derive(Debug, PartialEq)]
pub struct MemoryStats {
    /// 内存总字节数
    pub total_bytes: usize,
    
    /// 非零字节数（实际使用）
    pub used_bytes: usize,
    
    /// 零字节数（未使用）
    pub zero_bytes: usize,
    
    /// 内存使用百分比
    pub usage_percent: f32,
}

impl Memory {
    /// 将内存内容转储到文件
    ///
    /// # 参数
    /// * `file_path` - 输出文件路径
    /// * `options` - 转储配置选项
    ///
    /// # 返回值
    /// `std::io::Result<()>` - 成功或错误
    pub fn dump_to_file(
        &self,
        file_path: &str,
        options: &DumpOptions
    ) -> IoResult<()> {
        let mut file = std::fs::File::create(file_path)?;
        self.dump_to_writer(&mut file, options)
    }

    /// 将内存内容转储到任意写入器
    ///
    /// 这是核心转储函数，实现智能压缩和格式化
    ///
    /// # 参数
    /// * `writer` - 实现Write trait的对象
    /// * `options` - 转储配置选项
    ///
    /// # 返回值
    /// `std::io::Result<()>` - 成功或错误
    /// 将内存内容转储到任意写入器（针对大内存优化版）。
    ///
    /// 这个版本采用单遍扫描（Single-Pass）算法，在一次遍历中完成所有
    /// 统计、范围查找和格式化输出工作。这避免了对大内存区域的多次
    /// 扫描，显著提升了性能和响应速度。
    ///
    /// 由于统计信息是在遍历过程中计算的，因此摘要会显示在转储内容的末尾。
    ///
    /// # 参数
    /// * `writer` - 实现Write trait的对象
    /// * `options` - 转储配置选项
    ///
    /// # 返回值
    /// `std::io::Result<()>` - 成功或错误
    pub fn dump_to_writer(
        &self,
        writer: &mut dyn Write,
        options: &DumpOptions
    ) -> IoResult<()> {
        // === 静态头部信息 ===
        // 立即输出，用户可以马上看到反馈
        writeln!(writer, "--- RISC-V Memory Dump (Optimized Single-Pass) ---")?;
        writeln!(writer, "Base: 0x{:08X} | Size: {} bytes", self.base, self.size)?;
        writeln!(writer, "\n--- Memory Contents ---")?;

        // === 状态变量 (在单遍扫描中动态计算) ===
        let mut lines_dumped: usize = 0;
        let mut consecutive_empty: usize = 0;
        let mut used_bytes_count: usize = 0;
        let mut first_non_zero_addr: Option<u32> = None;
        let mut last_non_zero_addr: Option<u32> = None;

        let data_slice = self.get_data_slice();
        let data_len = data_slice.len();

        // === 主转储循环 (唯一的内存遍历) ===
        for chunk_idx in (0..data_len).step_by(options.bytes_per_line) {
            let current_addr = self.base + chunk_idx as u32;
            let end_idx = std::cmp::min(chunk_idx + options.bytes_per_line, data_len);
            let chunk = &data_slice[chunk_idx..end_idx];

            // --- 实时分析当前块 ---
            let mut non_zero_in_chunk = 0;
            for (i, byte) in chunk.iter().enumerate() {
                if *byte != 0 {
                    non_zero_in_chunk += 1;
                    let byte_addr = current_addr + i as u32;
                    if first_non_zero_addr.is_none() {
                        first_non_zero_addr = Some(byte_addr);
                    }
                    last_non_zero_addr = Some(byte_addr);
                }
            }
            used_bytes_count += non_zero_in_chunk;
            let is_empty = non_zero_in_chunk == 0;

            // === 空白行处理 ===
            if is_empty && options.compress_empty_lines {
                consecutive_empty += 1;
                continue; // 跳过空白行，进入下一次循环
            }

            // === 输出压缩摘要 ===
            if consecutive_empty > 0 {
                let start_addr = current_addr - (consecutive_empty * options.bytes_per_line) as u32;
                let end_addr = current_addr - 1;
                writeln!(
                    writer,
                    "{}[Omitted {} consecutive empty lines (0x{:08X} - 0x{:08X})]",
                    if options.show_line_numbers { "..." } else { "" },
                    consecutive_empty,
                    start_addr,
                    end_addr
                )?;
                consecutive_empty = 0;
            }

            // === 行数限制检查 ===
            if lines_dumped >= options.max_lines && options.max_lines > 0 {
                let remaining_bytes = data_len - chunk_idx;
                let remaining_lines = (remaining_bytes + options.bytes_per_line - 1) / options.bytes_per_line;
                writeln!(writer, "{}[Omitted {} more lines due to max_lines limit of {}]",
                    if options.show_line_numbers { "..." } else { "" },
                    remaining_lines,
                    options.max_lines
                )?;
                break; // 达到限制，终止循环
            }

            // --- 开始格式化并输出当前行 ---

            // === 行号输出 ===
            if options.show_line_numbers {
                write!(writer, "{:<4} ", lines_dumped + 1)?;
            }

            // === 地址输出 ===
            write!(writer, "0x{:08X}: ", current_addr)?;

            // === 十六进制字节输出 ===
            for byte in chunk {
                write!(writer, "{:02X} ", byte)?;
            }

            // === 行尾对齐 ===
            if chunk.len() < options.bytes_per_line {
                for _ in 0..(options.bytes_per_line - chunk.len()) {
                    write!(writer, "   ")?; // 每个字节占3个字符 ("XX ")
                }
            }

            // === ASCII表示输出 ===
            if options.show_ascii {
                write!(writer, " | ")?;
                for byte in chunk {
                    let c = *byte as char;
                    write!(writer, "{}",
                        if c.is_ascii_graphic() { c } else { '.' }
                    )?;
                }
            }

            writeln!(writer)?;
            lines_dumped += 1;
        }

        // === 处理循环结束后可能存在的末尾空白行 ===
        if consecutive_empty > 0 {
            let start_offset = data_len - (consecutive_empty * options.bytes_per_line);
            let start_addr = self.base + start_offset as u32;
            let end_addr = self.base + data_len as u32 - 1;
            writeln!(
                writer,
                "{}[Omitted {} consecutive empty lines (0x{:08X} - 0x{:08X})]",
                if options.show_line_numbers { "..." } else { "" },
                consecutive_empty,
                start_addr,
                end_addr
            )?;
        }

        // === 在末尾打印遍历后才得到的统计摘要 ===
        writeln!(writer, "\n--- Memory Analysis Summary ---")?;
        let total_bytes = data_len;
        let zero_bytes = total_bytes - used_bytes_count;
        let usage_percent = if total_bytes > 0 {
            (used_bytes_count as f32 / total_bytes as f32) * 100.0
        } else {
            0.0
        };

        writeln!(writer, "Total: {} bytes | Used: {} bytes | Zero: {} bytes | Usage: {:.2}%",
            total_bytes, used_bytes_count, zero_bytes, usage_percent)?;

        if let (Some(start), Some(end)) = (first_non_zero_addr, last_non_zero_addr) {
            let active_size = end - start + 1;
            writeln!(writer, "Active Range: 0x{:08X} - 0x{:08X} ({} bytes)", start, end, active_size)?;
        } else {
            writeln!(writer, "Active Range: Memory is entirely zero.")?;
        }

        // === 结束标记 ===
        writeln!(writer, "--- End of Dump ---")?;
        Ok(())
    }

    /// 获取内存统计信息
    ///
    /// 分析内存使用情况，返回统计结构体
    pub fn analyze(&self) -> MemoryStats {
        let data_slice = self.get_data_slice();
        let total_bytes = data_slice.len();
        let zero_bytes = data_slice.iter().filter(|&b| *b == 0).count();
        let used_bytes = total_bytes - zero_bytes;
        let usage_percent = (used_bytes as f32 / total_bytes as f32) * 100.0;
        
        MemoryStats {
            total_bytes,
            used_bytes,
            zero_bytes,
            usage_percent,
        }
    }
    
    /// 比较当前内存与另一个内存实例的差异
    ///
    /// # 参数
    /// * `other` - 要比较的另一个Memory实例
    ///
    /// # 返回值
    /// 返回所有不同字节的地址列表
    pub fn diff(&self, other: &Memory) -> Vec<u32> {
        let mut differences = Vec::new();
        let self_slice = self.get_data_slice();
        let other_slice = other.get_data_slice();
        
        // 检查基地址和大小是否相同
        if self.base != other.base || self.size != other.size {
            // 对于不同尺寸的内存，只能比较重叠部分
            let start_addr = std::cmp::max(self.base, other.base);
            let end_addr = std::cmp::min(
                self.base + self.size,
                other.base + other.size
            );
            
            if start_addr < end_addr {
                let self_start_offset = (start_addr - self.base) as usize;
                let other_start_offset = (start_addr - other.base) as usize;
                let length = (end_addr - start_addr) as usize;
                
                for i in 0..length {
                    if self_slice[self_start_offset + i] != other_slice[other_start_offset + i] {
                        differences.push(start_addr + i as u32);
                    }
                }
            }
            
            return differences;
        }
        
        // 对于相同尺寸和基地址的内存，直接比较
        for (i, (b1, b2)) in self_slice.iter().zip(other_slice.iter()).enumerate() {
            if b1 != b2 {
                differences.push(self.base + i as u32);
            }
        }
        
        differences
    }
    
    /// 查找特定字节模式
    ///
    /// # 参数
    /// * `pattern` - 要查找的字节模式切片
    ///
    /// # 返回值
    /// 返回所有匹配模式的起始地址列表
    pub fn find_pattern(&self, pattern: &[u8]) -> Vec<u32> {
        if pattern.is_empty() {
            return Vec::new();
        }
        
        self.get_data_slice().windows(pattern.len())
            .enumerate()
            .filter(|(_, window)| *window == pattern)
            .map(|(i, _)| self.base + i as u32)
            .collect()
    }

}

#[cfg(test)]
mod tests {
    use super::*;
    use std::io::Cursor;

    /// 创建测试内存实例
    ///
    /// 包含预设的测试数据模式
    fn create_test_memory() -> Memory {
        let mut mem: Memory = Memory::new(0x8000_0000, 256);
        let data_slice = mem.get_data_slice_mut();
        
        // 设置测试数据：
        data_slice[0x00..0x04].copy_from_slice(&[0xDE, 0xAD, 0xBE, 0xEF]); // "DEADBEEF"
        data_slice[0x10..0x14].copy_from_slice(&[0xCA, 0xFE, 0xBA, 0xBE]); // "CAFEBABE"
        data_slice[0x20..0x24].copy_from_slice(&[0x00, 0x00, 0x00, 0x00]); // 空白区域
        
        mem
    }

    /// 测试默认配置值
    #[test]
    fn test_dump_options_default() {
        let opts = DumpOptions::default();
        assert_eq!(opts.bytes_per_line, 16);
        assert_eq!(opts.max_lines, 1024);
        assert!(opts.show_ascii);
        assert!(opts.compress_empty_lines);
        assert!(opts.show_line_numbers);
    }
    
    /// 测试内存分析功能
    #[test]
    fn test_memory_analyze() {
        let mem = create_test_memory();
        let stats = mem.analyze();
        
        assert_eq!(stats.total_bytes, 256);
        assert_eq!(stats.used_bytes, 8); // DEADBEEF + CAFEBABE
        assert_eq!(stats.zero_bytes, 248);
        assert!(stats.usage_percent - 3.125 < 0.01); // 8/256 = 3.125%
    }
    
    /// 测试非零区域检测
    #[test]
    fn test_find_non_zero_range() {
        let mem = create_test_memory();
        let (start, end) = mem.find_non_zero_range();
        assert_eq!(start, 0);
        assert_eq!(end, 0x14 + 1); // 0x14是最后一个非零字节位置
    }
    
    /// 测试基本转储功能
    #[test]
    fn test_dump_to_writer() {
        let mem = create_test_memory();
        let mut output = Vec::new();
        let mut cursor = Cursor::new(&mut output);
        
        // 自定义配置
        let options = DumpOptions {
            bytes_per_line: 8,
            max_lines: 3,
            show_ascii: true,
            compress_empty_lines: true,
            show_line_numbers: true,
        };
        
        mem.dump_to_writer(&mut cursor, &options).unwrap();
        
        let dump_str = String::from_utf8(output).unwrap();
        
        // 验证关键内容
        assert!(dump_str.contains("0x80000000: DE AD BE EF"));
        assert!(dump_str.contains("0x80000010: CA FE BA BE"));
        assert!(dump_str.contains("[Omitted 1 consecutive empty lines"));
    }
    
    /// 测试内存差异比较
    #[test]
    fn test_diff() {
        let mem1 = create_test_memory();
        let mut mem2 = create_test_memory();

        // 修改一个字节
        let data_slice = mem2.get_data_slice_mut();
        data_slice[0x11] = 0xDD;
        
        let diff = mem1.diff(&mem2);
        assert_eq!(diff, vec![0x80000011]);
    }
    
    /// 测试模式查找功能
    #[test]
    fn test_find_pattern() {
        let mem = create_test_memory();
        let pattern = [0xCA, 0xFE, 0xBA, 0xBE]; // "CAFEBABE"
        let found = mem.find_pattern(&pattern);
        assert_eq!(found, vec![0x80000010]);
    }
    
    /// 测试空白行压缩功能
    #[test]
    fn test_dump_with_compressed_empty() {
        // 创建2KB内存，大部分为零
        let mut mem = Memory::new(0x80000000, 2048);
        let data_slice = mem.get_data_slice_mut();
        
        // 设置数据块：开头一小块，结尾一小块
        data_slice[0..4].copy_from_slice(&[0x01, 0x02, 0x03, 0x04]);
        data_slice[2000..2004].copy_from_slice(&[0x05, 0x06, 0x07, 0x08]);
        
        let mut output = Vec::new();
        let mut cursor = Cursor::new(&mut output);
        
        // 使用自定义选项确保压缩生效
        let options = DumpOptions {
            compress_empty_lines: true,
            max_lines: 100,
            ..Default::default()
        };
        
        mem.dump_to_writer(&mut cursor, &options).unwrap();
        
        let dump_str = String::from_utf8(output).unwrap();
        
        // 验证空白区域被压缩
        assert!(!dump_str.contains("0x80000010:")); // 空白区域地址
        assert!(!dump_str.contains("0x80000100:")); // 空白区域地址
        assert!(dump_str.contains("Omitted"));      // 压缩标记
        
        // 验证数据区域被保留
        assert!(dump_str.contains("0x80000000:")); // 第一块数据
        assert!(dump_str.contains("0x800007D0:")); // 第二块数据 (2000=0x7D0)
    }
    
    /// 测试末尾空白行压缩
    #[test]
    fn test_trailing_empty_lines() {
        // 创建256字节内存
        let mut mem = Memory::new(0x80000000, 256);
        let data_slice = mem.get_data_slice_mut();
        
        // 只在开头设置16字节数据
        data_slice[0..16].copy_from_slice(&[1; 16]);
        
        let mut output = Vec::new();
        let mut cursor = Cursor::new(&mut output);
        
        let options = DumpOptions {
            compress_empty_lines: true,
            ..Default::default()
        };
        
        mem.dump_to_writer(&mut cursor, &options).unwrap();
        
        let dump_str = String::from_utf8(output).unwrap();
        
        // 验证：只有第一行被输出，其余被压缩
        assert!(dump_str.contains("0x80000000:"));
        assert!(!dump_str.contains("0x80000010:"));
        assert!(dump_str.contains("Omitted 15 consecutive empty lines"));
    }
}